// ------------------------------------------
// T.Mock ExpectationBuilder
// ------------------------------------------


T.Mock.ExpectationBuilder = function( mockery, adaptee, expectation ) 
{
	this.mockery = mockery;
	
	this.adaptee = adaptee;
	this.expectation = expectation;
};

T.Mock.ExpectationBuilder.prototype =
{
	setupAdaptee: function( )
	{
		this.mockery.adaptees.push( this.adaptee );
		
		this.adaptee.__invocationNo = 0;
		this.adaptee.__expectations = [ ];
		this.adaptee.__placeholder = this.adaptee.__placeholder || { };
	},
	
	saveExisting: function( )
	{
		var name = this.expectation.method;
		
		if( this.adaptee.__placeholder[ name ] ) { return; }
		if( !this.adaptee[ name ] ) { this.adaptee.__placeholder[ name ] = T.Mock.StubMethod; return; } 
		
		this.adaptee.__placeholder[ name ] = this.adaptee[ name ];
	},
	
	addExpectation: function( )
	{
		var 	expectation = this.expectation,
				name = expectation.method;
		
		expectation.args = expectation.args || [ ];
		expectation.fRun = expectation.fRun || function( ) { };
		
		expectation.calls = Lang.isNumber( expectation.calls )  ? expectation.calls : 1;
		expectation.actualCalls = 0;
		
		this.mockery.expectationArguments( name, expectation.args );
		if( expectation.calls <= 0 ) { this.adaptee[ name ] = T.Mock.DisabledMethod( name ); return; }
		
		this.adaptee.__expectations.push( expectation );
		this.adaptee[ name ] = Env.bind( this.mockedInvocation, this );
	},
	
	mockedInvocation: function( )
	{
		try
		{
			var expectation = this.getExpectation( );
			
			Assert.areEqual( expectation.args.length, arguments.length, "Method " + name + "( ) passed incorrect number of arguments." );
			for( var i=0, len=expectation.args.length; i < len; i++) { expectation.args[ i ].verify( arguments[ i ] ); }

			expectation.fRun.apply(this, arguments);
            if ( expectation.error ) { throw expectation.error; }
            
            return expectation.returns;
		}
		catch( err ) { Test.Runner._handleError( err ); }
	},
	
	getExpectation: function( )
	{
		var 	expectation, 
				name = this.expectation.method,
				expectations = this.adaptee.__expectations,
				invocationNo = this.adaptee.__invocationNo;
				
		if( invocationNo >= expectations.length ) { Assert.fail( "Invocation count  for " + name + "( ) out of range." ); }
		
		expectation = expectations[ invocationNo ];
		if( name !== expectation.method ) { Assert.fail( "Expected invocation of " + name + "( ) instead of " + expectation.method + "( )." ); }
		
		expectation.actualCalls ++;
		if( expectation.actualCalls === expectation.calls ) { this.adaptee.__invocationNo++; }
		
		return expectation;
	}
};